package com.backend.modules.task.service.impl;

import com.backend.common.event.SubmissionCreatedEvent;
import com.backend.common.exception.BusinessException;
import com.backend.common.utils.SecurityUtils;
import com.backend.modules.notification.enums.NotificationType;
import com.backend.modules.notification.service.NotificationService;
import com.backend.modules.system.entity.SysUser;
import com.backend.modules.system.repository.SysUserRepository;
import com.backend.modules.task.convert.TaskConvert;
import com.backend.modules.task.dto.StudentTaskQueryDTO;
import com.backend.modules.task.dto.TaskSubmissionDTO;
import com.backend.modules.task.entity.Task;
import com.backend.modules.task.entity.TaskSubmission;
import com.backend.modules.task.entity.TaskSubmissionFile;
import com.backend.modules.task.enums.SubmissionStatus;
import com.backend.modules.task.enums.TaskStatus;
import com.backend.modules.task.repository.TaskRepository;
import com.backend.modules.task.repository.TaskSubmissionRepository;
import com.backend.modules.task.repository.TaskSubmissionFileRepository;
import com.backend.modules.task.service.AIAuditService;
import com.backend.modules.task.service.StudentTaskService;
import com.backend.modules.task.service.TaskSubmissionService;
import com.backend.modules.task.vo.TaskSubmissionFileVO;
import com.backend.modules.task.vo.TaskVO;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
public class StudentTaskServiceImpl implements StudentTaskService {

    private final TaskRepository taskRepository;
    private final TaskSubmissionRepository submissionRepository;
    private final SysUserRepository userRepository;
    private final NotificationService notificationService;
    private final TaskSubmissionFileRepository taskSubmissionFileRepository;
    private final TaskSubmissionService taskSubmissionService;
    private final ApplicationEventPublisher eventPublisher;

    @Override
    public Page<TaskVO> page(StudentTaskQueryDTO query, Pageable pageable) {
        Specification<Task> spec = (root, criteriaQuery, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            // 名称模糊查询
            if (StringUtils.hasText(query.getName())) {
                predicates.add(cb.like(root.get("name"), 
                    "%" + query.getName() + "%"));
            }
            
            // 任务状态查询
            if (query.getStatus() != null) {
                LocalDateTime now = LocalDateTime.now();
                Long studentId = SecurityUtils.getCurrentUserId();
                
                switch (query.getStatus()) {
                    case EXPIRED: // 已截止, 未提交
                        predicates.add(cb.lessThan(root.get("deadline"), now));
                        // 未提交或被驳回的任务
                        Subquery<TaskSubmission> expiredSubquery = criteriaQuery.subquery(TaskSubmission.class);
                        Root<TaskSubmission> expiredRoot = expiredSubquery.from(TaskSubmission.class);
                        expiredSubquery.select(expiredRoot)
                            .where(
                                cb.and(
                                    cb.equal(expiredRoot.get("task"), root),
                                    cb.equal(expiredRoot.get("student").get("id"), studentId)
                                )
                            );
                        predicates.add(cb.not(cb.exists(expiredSubquery)));
                        break;
                        
                    case PENDING:  // 待提交，
                        predicates.add(cb.greaterThanOrEqualTo(root.get("deadline"), now));
                        // 未提交
                        Subquery<TaskSubmission> pendingSubquery = criteriaQuery.subquery(TaskSubmission.class);
                        Root<TaskSubmission> pendingRoot = pendingSubquery.from(TaskSubmission.class);
                        pendingSubquery.select(pendingRoot)
                            .where(
                                cb.and(
                                    cb.equal(pendingRoot.get("task"), root),
                                    cb.equal(pendingRoot.get("student").get("id"), studentId)
                                )
                            );
                        predicates.add(cb.not(cb.exists(pendingSubquery)));
                        break;
                        
                    case REVIEWING: // 待审核
                        Subquery<TaskSubmission> reviewingSubquery = criteriaQuery.subquery(TaskSubmission.class);
                        Root<TaskSubmission> reviewingRoot = reviewingSubquery.from(TaskSubmission.class);
                        reviewingSubquery.select(reviewingRoot)
                            .where(
                                cb.and(
                                    cb.equal(reviewingRoot.get("task"), root),
                                    cb.equal(reviewingRoot.get("student").get("id"), studentId),
                                    cb.or(
                                        cb.equal(reviewingRoot.get("status"), SubmissionStatus.PENDING.name()),
                                        cb.equal(reviewingRoot.get("status"), SubmissionStatus.TEACHER_REVIEWING.name())
                                    )
                                )
                            );
                        predicates.add(cb.exists(reviewingSubquery));
                        break;
                        
                    case APPROVED: // 已通过
                        Subquery<TaskSubmission> approvedSubquery = criteriaQuery.subquery(TaskSubmission.class);
                        Root<TaskSubmission> approvedRoot = approvedSubquery.from(TaskSubmission.class);
                        approvedSubquery.select(approvedRoot)
                            .where(
                                cb.and(
                                    cb.equal(approvedRoot.get("task"), root),
                                    cb.equal(approvedRoot.get("student").get("id"), studentId),
                                    cb.equal(approvedRoot.get("status"), SubmissionStatus.APPROVED.name())
                                )
                            );
                        predicates.add(cb.exists(approvedSubquery));
                        break;
                        
                    case REJECTED: // 已驳回
                        Subquery<TaskSubmission> rejectedSubquery = criteriaQuery.subquery(TaskSubmission.class);
                        Root<TaskSubmission> rejectedRoot = rejectedSubquery.from(TaskSubmission.class);
                        rejectedSubquery.select(rejectedRoot)
                            .where(
                                cb.and(
                                    cb.equal(rejectedRoot.get("task"), root),
                                    cb.equal(rejectedRoot.get("student").get("id"), studentId),
                                    cb.equal(rejectedRoot.get("status"), SubmissionStatus.REJECTED.name())
                                )
                            );
                        predicates.add(cb.exists(rejectedSubquery));
                        break;
                }
            }
            
            // 时间范围查询
            if (query.getStartTime() != null) {
                predicates.add(cb.greaterThanOrEqualTo(
                    root.get("deadline"), query.getStartTime()));
            }
            if (query.getEndTime() != null) {
                predicates.add(cb.lessThanOrEqualTo(
                    root.get("deadline"), query.getEndTime()));
            }
            
            // 只查询当前学生所在班级的任务
            Long studentId = SecurityUtils.getCurrentUserId();
            SysUser student = userRepository.findById(studentId)
                    .orElseThrow(() -> new BusinessException("用户不存在"));

            predicates.add(cb.equal(root.get("classId"), student.getDepartment().getId()));
            
            // 提交状态查询
            if (query.getSubmitted() != null) {
                Subquery<TaskSubmission> subquery = criteriaQuery.subquery(TaskSubmission.class);
                Root<TaskSubmission> submissionRoot = subquery.from(TaskSubmission.class);
                
                subquery.select(submissionRoot)
                        .where(
                            cb.and(
                                cb.equal(submissionRoot.get("task"), root),
                                cb.equal(submissionRoot.get("student").get("id"), studentId)
                            )
                        );
                
                if (query.getSubmitted()) {
                    predicates.add(cb.exists(subquery));
                } else {
                    predicates.add(cb.not(cb.exists(subquery)));
                }
            }
            
            return cb.and(predicates.toArray(new Predicate[0]));
        };
        
        // 转换结果
        return taskRepository.findAll(spec, pageable)
                .map(task -> {
                    TaskVO vo = TaskConvert.convert(task);
                    // 查询提交状态
                    TaskSubmission submission = submissionRepository
                            .findFirstByTaskIdAndStudentIdOrderBySubmitTimeDesc(
                                task.getId(), SecurityUtils.getCurrentUserId()).orElse(null);
                    
                    // 判断任务状态
                    LocalDateTime now = LocalDateTime.now();
                    if (submission == null) {
                        // 未提交
                        vo.setSubmitStatus(now.isAfter(task.getDeadline()) ? 
                            TaskStatus.EXPIRED.name() :
                            TaskStatus.PENDING.name());
                    } else {
                        // 已提交，根据提交状态判断
                        switch (SubmissionStatus.valueOf(submission.getStatus())) {
                            case PENDING:
                            case TEACHER_REVIEWING:
                                vo.setSubmitStatus(TaskStatus.REVIEWING.name());
                                break;
                            case APPROVED:
                                vo.setSubmitStatus(TaskStatus.APPROVED.name());
                                break;
                            case REJECTED:
                                // 如果已驳回且已过期，则显示已截止
                                vo.setSubmitStatus(now.isAfter(task.getDeadline()) ?
                                    TaskStatus.EXPIRED.name() :
                                    TaskStatus.REJECTED.name());
                                break;
                        }
                    }

                    // 设置其他信息
                    if (submission != null) {
                        vo.setSubmitted(true);
                        vo.setSubmissionId(submission.getId());
                        vo.setSubmissionStatus(submission.getStatus());
                        vo.setSubmissionTime(submission.getSubmitTime());
                    }
                    if (task.getTeacher() != null) {
                        vo.setTeacherName(task.getTeacher().getRealName());
                    }

                    return vo;
                });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSubmission(Long taskId, TaskSubmissionDTO dto) {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        SysUser currentStudent = userRepository.findById(currentUserId)
            .orElseThrow(() -> new BusinessException("学生不存在"));
        // 获取最新提交记录
        TaskSubmission submission = submissionRepository
                .findFirstByTaskIdAndStudentIdOrderBySubmitTimeDesc(
                    taskId, SecurityUtils.getCurrentUserId()).orElseThrow(() -> new BusinessException("提交记录不存在"));
                
        // 检查状态
        if (SubmissionStatus.APPROVED.name().equals(submission.getStatus())) {
            throw new BusinessException("已经审核通过的上传不能修改");
        }
        
        // 检查截止时间
        if (LocalDateTime.now().isAfter(submission.getTask().getDeadline())) {
            throw new BusinessException("任务已截止，无法修改");
        }

        // 更新提交信息
        submission.setComment(dto.getComment());
        submission.setSubmitTime(LocalDateTime.now());
        
        // 处理文件上传
        addFileToSubmission(dto, submission);
        
        // 重置状态为待审核
        submission.setStatus(SubmissionStatus.PENDING.name());
        
        submissionRepository.save(submission);
        
        // 发送通知给教师
        notificationService.send(
            submission.getTask().getCreatorId(),
            "提交更新: " + submission.getTask().getName(),
            String.format("学生[%s:%s]更新了提交", SecurityUtils.getCurrentUsername(),currentStudent.getRealName()),
            NotificationType.SUBMISSION_SUCCESS,
            submission.getId()
        );
        
        // 发布事件触发AI审核流程
        eventPublisher.publishEvent(new SubmissionCreatedEvent(this, submission));
    }

    private  void addFileToSubmission(TaskSubmissionDTO dto, TaskSubmission submission) {
        // 删除 该提交的所有文件
        taskSubmissionFileRepository.deleteBySubmissionId(submission.getId());
        submission.getFiles().clear();
        AtomicInteger i = new AtomicInteger(1);
        dto.getFiles().forEach(fileDTO -> {
            TaskSubmissionFile file = new TaskSubmissionFile();
            file.setFileName(fileDTO.getFileName());
            file.setFileUrl(fileDTO.getFileUrl());
            file.setFileSize(fileDTO.getFileSize());
            file.setFileType(fileDTO.getFileType());
            file.setSort(i.getAndIncrement());
            submission.addFile(file);
        });
    }


    @Override
    public TaskSubmission getSubmissionById(Long submissionId) {
        TaskSubmission submission = submissionRepository.findByIdWithDetails(submissionId)
                .orElseThrow(() -> new BusinessException("提交记录不存在"));
                
        // 检查是否是当前学生的提交
        if (!submission.getStudent().getId().equals(SecurityUtils.getCurrentUserId())) {
            throw new BusinessException("无权访问该提交记录");
        }

        return submission;
    }

    @Override
    public TaskVO getTaskDetail(Long taskId) {
        // 获取任务信息
        Task task = taskRepository.findById(taskId)
                .orElseThrow(() -> new BusinessException("任务不存在"));
                
        // 检查是否是当前学生所在班级的任务
        Long studentId = SecurityUtils.getCurrentUserId();
        SysUser student = userRepository.findById(studentId)
                .orElseThrow(() -> new BusinessException("用户不存在"));

        if (!task.getClassId().equals(student.getDepartment().getId())) {

            throw new BusinessException("无权访问该任务");
        }
        
        // 转换为VO并返回
        TaskVO vo = TaskConvert.convert(task);
        
        // 查询提交状态
        TaskSubmission submission = submissionRepository
            .findFirstByTaskIdAndStudentIdOrderBySubmitTimeDesc(
                task.getId(), SecurityUtils.getCurrentUserId()).orElse(null);

        // 判断任务状态
        LocalDateTime now = LocalDateTime.now();
        if (submission == null) {
            // 未提交
            vo.setSubmitStatus(now.isAfter(task.getDeadline()) ?
                TaskStatus.EXPIRED.name() :
                TaskStatus.PENDING.name());
        } else {
            // 已提交，根据提交状态判断
            switch (SubmissionStatus.valueOf(submission.getStatus())) {
                case PENDING:
                    vo.setSubmitStatus(TaskStatus.REVIEWING.name());
                    break;
                case APPROVED:
                    vo.setSubmitStatus(TaskStatus.APPROVED.name());
                    break;
                case REJECTED:
                    // 如果已驳回且已过期，则显示已截止
                    vo.setSubmitStatus(now.isAfter(task.getDeadline()) ?
                        TaskStatus.EXPIRED.name() :
                        TaskStatus.REJECTED.name());
                    break;
            }
        }

        if (submission != null) {
            vo.setSubmitted(true);
            vo.setSubmissionId(submission.getId());
            vo.setSubmissionStatus(submission.getStatus());
            vo.setSubmissionTime(submission.getSubmitTime());
            vo.setSubmissionComment(submission.getReviewComment());
            TaskSubmission taskSubmission = getSubmissionById(submission.getId());
            vo.setFiles(taskSubmission.getFiles().stream().map(file -> {
                TaskSubmissionFileVO fileVO = new TaskSubmissionFileVO();
                fileVO.setId(file.getId());
                fileVO.setFileName(file.getFileName());
                fileVO.setFileUrl(file.getFileUrl());
                fileVO.setFileSize(file.getFileSize());
                fileVO.setFileType(file.getFileType());
                fileVO.setSort(file.getSort());
                return fileVO;
            }).collect(Collectors.toList()));
        }
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submit(Long taskId, TaskSubmissionDTO dto) {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        SysUser currentStudent = userRepository.findById(currentUserId)
                .orElseThrow(() -> new BusinessException("学生不存在"));
        // 检查任务是否存在且未截止
        Task task = taskRepository.findById(taskId)
                .orElseThrow(() -> new BusinessException("任务不存在"));

        if (task.getDeadline().isBefore(LocalDateTime.now())) {
            throw new BusinessException("任务已截止");
        }

        // 创建或更新提交记录
        TaskSubmission submission = submissionRepository
                .findFirstByTaskIdAndStudentIdOrderBySubmitTimeDesc(taskId, currentUserId)
                .orElseGet(() -> {
                    TaskSubmission newSubmission = new TaskSubmission();
                    newSubmission.setTask(task);
                    newSubmission.setCreatorId(currentUserId);
                    newSubmission.setStudent(currentStudent);
                    newSubmission.setCreateTime(LocalDateTime.now());
                    newSubmission.setUpdateTime(LocalDateTime.now());
                    return newSubmission;
                });

        submission.setComment(dto.getComment());
        submission.setSubmitTime(LocalDateTime.now());
        
        // 初始状态设置为待审核
        submission.setStatus(SubmissionStatus.PENDING.name());

        // 处理文件上传
        addFileToSubmission(dto, submission);

        submissionRepository.save(submission);
        
        // 发送通知给教师
        notificationService.send(
            task.getCreatorId(),
            "新的提交: " + task.getName(),
            String.format("学生[%s:%s]提交了任务", SecurityUtils.getCurrentUsername(),currentStudent.getRealName()),
            NotificationType.SUBMISSION_SUCCESS,
            submission.getId()
        );
        
        // 发布事件触发AI审核流程
        eventPublisher.publishEvent(new SubmissionCreatedEvent(this, submission));
    }

} 